/*
调用的外部函数
U Channel
U D2DCADPreambleTime
U D2DCADTimer
U LoRaMacRegion
U LoRaMacState
U McpsIndication
U Radio
U RegionRxConfig
U RxSlot
U RxWindow1Config
U RxWindowSetup
U TimerGetCurrentTime
U TimerSetValue
U TimerStart
U TimerStop
U __aeabi_d2uiz
U __aeabi_ddiv
U __aeabi_i2d
U ceil
U g_log_level
U printf
*/

#include <stdint.h>
#include <stdbool.h>
#include <math.h>
#include "radio.h"
#include "timeServer.h"
#include "LoRaMac.h"
#include "region/Region.h"
#include "LoRaMacClassD.h" 

/*只读数据变量*/
const uint16_t RxPreambleMs[6] = {0x107, 0x84, 0x42, 0x21, 0x11, 9};
const double SymbolTime[6] = {32.768, 16.384, 8.192, 4.096, 2.048, 1.024};

/*文件中的变量(未初始化)*/ 
bool D2DCADDetecting;
RxConfigParams_t RxWindow3Config;
uint8_t D2DCadDetectedNum;
int32_t LoRaMacCADSkipCnt;


extern TimerEvent_t D2DCADTimer;
extern DeviceClass_t LoRaMacDeviceClass;
extern uint16_t D2DCADPreambleTime;
extern uint32_t LoRaMacState;
extern LoRaMacRxSlot_t RxSlot;
extern LoRaMacRegion_t LoRaMacRegion;
extern LoRaMacParams_t LoRaMacParams;
extern McpsIndication_t McpsIndication;
extern RxConfigParams_t RxWindow1Config;
extern uint8_t Channel;
/*----------------------函数----------------------*/
/*!
 * bool LoRaMacClassDISCADDetecting(void)
 */
bool LoRaMacClassDISCADDetecting(void)
{
   return D2DCADDetecting;
}

/*!
 * void LoRaMacPostponeCADAfterD2DUp(uint32_t reservetime)
 */
void LoRaMacPostponeCADAfterD2DUp(uint32_t reservetime)
{
    TimerStop(&D2DCADTimer);
    TimerSetValue(&D2DCADTimer, reservetime);
    TimerStart(&D2DCADTimer);
}

/*!
 * void LoRaMacStartCADTimer(void)
 */
void LoRaMacStartCADTimer(void)
{
    int val;

    TimerStop(&D2DCADTimer); 
    if(3 == LoRaMacDeviceClass){
        val = D2DCADPreambleTime - RxPreambleMs[RxWindow3Config.Datarate] - 0x50;
       
        if((val < 0) || (D2DCADPreambleTime <= val)){
            val = D2DCADPreambleTime;
        }
        TimerSetValue(&D2DCADTimer, val);
        TimerStart(&D2DCADTimer);
    }
}

/*!
 * void LoRaMacClassDCADDone(bool channelActivityDetected)  TBD
 */
/*
  ===========================================================================

 Segment type: Pure code
               void LoRaMacClassDCADDone(bool channelActivityDetected)
               
               

 =============== S U B R O U T I N E =======================================
*/
void LoRaMacClassDCADDone(bool channelActivityDetected)
{
    D2DCADDetecting = 0;
    if(0 != channelActivityDetected){
        if((LoRaMacState & 3) == 0){
            D2DCadDetectedNum++;
            if(D2DCadDetectedNum == 2){
                D2DCadDetectedNum = 0;
                TimerStop(&D2DCADTimer);
                Radio.Standby();
                LoRaMacState |= LORAMAC_RX;
                RxWindow3Config.PreambleLen = (uint32_t)ceil((double)D2DCADPreambleTime/RxPreambleMs[RxWindow3Config.Datarate]);
                if(RegionRxConfig(LoRaMacRegion, &RxWindow3Config, ( int8_t * )&McpsIndication.RxDatarate) == true){
                    RxWindowSetup( RxWindow3Config.RxContinuous, LoRaMacParams.MaxRxWindow );
                    RxSlot = 3;
                    printf("Info: start Rx after CadDetected, Rx at dr %d, preambleLen:%d\r\n", McpsIndication.RxDatarate, RxWindow3Config.PreambleLen);                    
                }
            }else{
                Radio.Sleep();
                TimerStop(&D2DCADTimer);
                TimerSetValue(&D2DCADTimer, 0x50);
                TimerStart(&D2DCADTimer);
            }
        }else{
            Radio.Sleep();
            LoRaMacStartCADTimer();
        }

    }else{
        D2DCADDetecting |= 1;
        Radio.Sleep();
        D2DCadDetectedNum = 0;                   
    }
}

/*!
 * void OnD2DCADTimerEvent(void) 
 */
void OnD2DCADTimerEvent(void)
{
    LoRaMacStartCADTimer();

    if((LoRaMacState & 3) != 0){
        if(++LoRaMacCADSkipCnt > 0x64){
            printf("Warning!!! CAD Skip Count exceed 100 \r\n");
        }
    }else{
        //printf("Info: Start CAD. \r\n");
        LoRaMacCADSkipCnt = 0;
        Radio.Standby();
        D2DCADDetecting = 1;
        RegionRxConfig(LoRaMacRegion, &RxWindow3Config, ( int8_t * )&McpsIndication.RxDatarate);
        Radio.StartCad(1);
    }   
}

/*!
 * LoRaMacStatus_t LoRaMacClassDSwitchClass(void)  
 */
 /*
  ===========================================================================

 Segment type: Pure code
               LoRaMacClassDSwitchClass
               
               

 =============== S U B R O U T I N E =======================================
 */
LoRaMacStatus_t LoRaMacClassDSwitchClass(void)
{
    RxWindow3Config.Channel = Channel;
    RxWindow3Config.Datarate = 5;
    RxWindow3Config.DownlinkDwellTime = LoRaMacParams.DownlinkDwellTime;
    RxWindow3Config.Bandwidth = RxWindow1Config.Bandwidth;
    RxWindow3Config.WindowTimeout = RxWindow1Config.WindowTimeout;
    RxWindow3Config.RxContinuous = 0;
    RxWindow3Config.PreambleLen = (uint32_t)ceil(D2DCADPreambleTime/1.024);
    RxWindow3Config.RxSlot = 3;
    printf("Info: Switch  to Class D. \r\n");
    return 0; 
}
















